/*
 * The X-Minou Projet
 * X-Minou is a text, irc like chat program for
 * local users of Unix system
 *
 * Author :  RaX| <raxxx.fr@gmail.com>
 *
 * Xminou in a free software released as-is.
 */

#include <csignal>
#include <cstdlib>
#include <cstring>
#include <clocale>
#include <vector>
#include <sstream>

#include <sys/ioctl.h>

#include "xminou_intf.hh"
#include "xminou_tailf.hh"
#include "xminou.hh"

void resize_intf (int);
void redraw_intf (void);

static WINDOW *top_menu_bar;
static WINDOW *center_view_window;
static WINDOW *bottom_write_entry;

NCursesIntf::NCursesIntf (void) : write_obj (), u ()
{

  initscr ();
  start_color ();

  init_pair (1, COLOR_BLACK, COLOR_WHITE);
  init_pair (2, COLOR_WHITE, COLOR_BLUE);

  top_menu_bar = subwin (stdscr, 1, stdscr->_maxx - 1, 0, 1);
 
  std::stringstream top_bar;
  top_bar << APP_NAME << " " << APP_VERSION 
          << " Nom de code: Mangouste intrepide"; 

  wbkgd (top_menu_bar, COLOR_PAIR (1));
  wprintw (top_menu_bar, top_bar.str ().c_str ());

  center_view_window = subwin (stdscr, stdscr->_maxy - 4,\
                                       stdscr->_maxx - 1, 2, 1);
  wbkgd (center_view_window, COLOR_PAIR (2));

  scrollok (center_view_window, TRUE);

  bottom_write_entry = subwin (stdscr, 1, stdscr->_maxx - 1,\
                                       stdscr->_maxy - 1, 1);
  wbkgd (bottom_write_entry, COLOR_PAIR (2));
  scrollok (bottom_write_entry, TRUE);

  refresh ();

  std::signal (SIGWINCH, resize_intf);

  if (pthread_create (&view_thread, NULL, file_reader_thread, NULL) < 0)
    exit (EXIT_FAILURE);

  usleep (500);

  std::string u_list = "";
  std::vector <std::string> v = u.who ();

  for (unsigned int i = 0; i < v.size (); i++)
   {
    std::string p;
    p = v.at (i);

    u_list += p.substr (p.find (":") + 1);
    if (i != v.size () -1)
      u_list += ", ";
   }

  wprintw (center_view_window, " *** Welcome on Xminou++ ! ***\n"\
           " *** Who is here ? %s ***\n\n",\
           u_list.c_str ());

  show_history ();

  write_obj.send_action ("has joined");
  u.join ();

}

void
NCursesIntf::run (void)
{

  /* FIXME: Allocate dynamic size */
  char *str = new char [512];

  std::string u_action = "/";
  u_action += whoami ();

  while (TRUE)
   {
    std::memset (str, 0, sizeof 512);
    wscanw (bottom_write_entry, (char*)"%[^\n]510s", str);
    wclear (bottom_write_entry);
    wrefresh (bottom_write_entry);

    std::string line (str);

    if (line == "/q" || line == "/quit" || line == "/exit")
      break;
    else if (cmd_cmp (str, "/action") ||\
              cmd_cmp (str, "/me") ||\
              cmd_cmp (str, u_action.c_str ()))
      write_action (str);
    else if (cmd_cmp (str, "/miaou") || line == "/miaou")
      write_miaou (str);
    else if (cmd_cmp (str, "/homer") || line == "/homer")
      write_homer (str);
    else if (cmd_cmp (str, "/bugs") || line == "/bugs")
      write_bugs (str);
    else if (line == "/l" || line == "/list" || line == "/who")
      show_list ();
    else if (line == "/history" || line == "/ll")
      show_history ();
    else if (line == "/help" || line == "/?")
      show_help ();
    else if (line == "/clear" || line == "cls")
      clear ();
    else if (line == "/erase")
     {
      wprintw (center_view_window, "\n* list not yet implemented\n\n");
      wrefresh (center_view_window);
     }
    else
      write_obj.send_message (std::string (str));
 
   }

  delete []str;

}

bool
NCursesIntf::cmd_cmp (char *src, const char *cmd)
{

  std::string src_str (src);

  int space_pos = src_str.find (" ");

  if (space_pos == std::string::npos)
    return false;

  return (src_str.substr (0, space_pos) == std::string (cmd));

}

void
NCursesIntf::show_help (void)
{

  wprintw (center_view_window,    
    "* available command are :\n"\
    "	    /? or /help: show this\n"\
    "	    /clear: clear the chat area\n"\
    "	    /who or /list: show the users list\n"\
    "	    /me [ACTION]: display an user action\n"\
    "	    /erase: erase the server chat log\n"\
    "	    /list or /l: show the current user list.\n"\
    "	    /history or /ll: show chat history.\n"\
    "	    /bugs [MESSAGE]: Bugs Bunny say your custom message\n"\
    "	    /miaou [MESSAGE]: a small cat say your custom message\n"\
    "	    /homer [MESSAGE]: Homer say your message\n"\
    "	    /quit or /exit: quit the chat room\n\n");

  wrefresh (center_view_window);

}

void
NCursesIntf::show_history (void)
{

  Tailf::Tailf *last_log = new Tailf::Tailf ();

  wprintw (center_view_window, last_log->get_lastline (stdscr->_maxy - 9));
  wrefresh (center_view_window);

  delete last_log;

}

void
NCursesIntf::show_list (void)
{

  std::string u_list = "";
  std::vector <std::string> v = u.who ();

  u_list += "\n* Users list ******************************\n";

  for (unsigned int i = 0; i < v.size (); i++)
  {
   std::string p;
   p = v.at (i);

   u_list += "("\
          + p.substr (0,p.find (":"))\
          + ") "\
          + p.substr (p.find (":") + 1) + "\n";
  }

  u_list += "*******************************************\n\n";

  wprintw (center_view_window, u_list.c_str ());
  wrefresh (center_view_window);

}

void
NCursesIntf::write_action (std::string str)
{

  std::string src_str (str);
  write_obj.send_action (src_str.substr (src_str.find (" ") + 1));

}

void
NCursesIntf::write_miaou (std::string str)
{

  std::string src_str (str);

  int i = src_str.find (" ");
  
  if (i != std::string::npos)
    write_obj.easter_egg_minou (src_str.substr ( i + 1));
  else
    write_obj.easter_egg_minou ();

}

void
NCursesIntf::write_homer (std::string str)
{

  std::string src_str (str);
  
  int i = src_str.find (" ");

  if (i != std::string::npos)
    write_obj.easter_egg_homer (src_str.substr ( i + 1));
  else
    write_obj.easter_egg_homer ();

}

void
NCursesIntf::write_bugs (std::string str)
{

  std::string src_str (str);

  int i = src_str.find (" ");

  if (i != std::string::npos)
   write_obj.easter_egg_bugs (src_str.substr ( i + 1));
  else
   write_obj.easter_egg_bugs ();

}

void
NCursesIntf::clear (void)
{

  wclear (center_view_window);
  wrefresh (center_view_window);

}

NCursesIntf::~NCursesIntf (void)
{

  pthread_cancel (view_thread);

  u.part ();

  write_obj.send_quit_action ("bye bye!");
  endwin ();

}

/* FIXME: Remove it, if you can't make this */

void
resize_intf (int sig)
{

  struct winsize s;

  ioctl(fileno(stdout), TIOCGWINSZ, &s);

  if (s.ws_row > 10 && s.ws_col > 10)
   {
    resizeterm (s.ws_row, s.ws_col);
    redraw_intf ();
   }

  (void)sig;

}

void
redraw_intf (void)
{

	clear ();

  werase (top_menu_bar);
  wresize (top_menu_bar, 1, stdscr->_maxx - 1);
  wbkgd (top_menu_bar, COLOR_PAIR (1));

  wresize (center_view_window, stdscr->_maxy - 4, stdscr->_maxx - 1);
  wbkgd (center_view_window, COLOR_PAIR (2));

  werase (bottom_write_entry);
  mvderwin (bottom_write_entry, stdscr->_maxy - 1, 1);
  wresize (bottom_write_entry, 1, stdscr->_maxx - 1);
  wbkgd (bottom_write_entry, COLOR_PAIR (2));

  std::stringstream top_bar;
  top_bar << APP_NAME << " " << APP_VERSION 
          << " Nom de code: Mangouste intrepide"; 

  wprintw (top_menu_bar, top_bar.str ().c_str ());

  refresh ();

}


void*
file_reader_thread (void *arg)
{

  std::ifstream file (SOCKET_FILE);

  if (file.is_open ())
   {
    file.seekg (0, std::ios::end);
   
    for (;;usleep (10))
     {
      std::string line;

      if (file.fail ())
        file.clear ();
          
      std::getline (file, line);
      if (!line.empty ())
       {
        line += "\n";
        wprintw (center_view_window, line.c_str ());    
        wrefresh (center_view_window);
       }
     }
   }

  pthread_exit (0);

  (void)arg;

}

